package com.onlyxiahui.extend.query.hibernate.syntax.data;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.onlyxiahui.extend.query.hibernate.parameter.ValueOption;
import com.onlyxiahui.extend.query.hibernate.parameter.ValueOptionInfo;
import com.onlyxiahui.extend.query.hibernate.parameter.ValueOptionType;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.Bracket;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.BracketGroup;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.BracketGroups;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.Brackets;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.Condition;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.Conditions;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.Like;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.OrderBy;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.OrderBys;
import com.onlyxiahui.extend.query.hibernate.syntax.annotation.QueryIgnore;
import com.onlyxiahui.extend.query.hibernate.util.DbReflectUtil;
import com.onlyxiahui.extend.query.hibernate.util.QueryUtil;
import com.onlyxiahui.extend.query.hibernate.util.DbStringUtil;

/**
 * Description <br>
 * Date 2020-05-26 12:00:36<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */

public class QueryHandleUtil {

	public static QueryHandleData get(Object value) {

		QueryHandleData data = new QueryHandleData();
		List<OrderByInfo> orderByInfos = new ArrayList<>();
		List<ValueOptionInfo> options = new ArrayList<>();
		List<QueryColumn> columns = new ArrayList<>();
		Map<String, BracketInfo> bracketMap = new HashMap<>(50);

		if (null != value) {

			Class<?> calssType = value.getClass();
			orderByInfos = getOrderByInfos(calssType);
			bracketMap = getBracketInfoMap(calssType);

			if (value instanceof Map) {
				Map<?, ?> map = (Map<?, ?>) value;
				for (Object key : map.keySet()) {
					if (null != key) {
						QueryColumn qc = getQueryColumn(key.toString(), null, null);
						columns.add(qc);
					}
				}
			} else {

				List<PropertyDescriptor> propertyDescriptorList = QueryUtil.getReadMethodList(calssType);
				for (PropertyDescriptor p : propertyDescriptorList) {
					String name = p.getName();
					Field f = DbReflectUtil.getField(calssType, Object.class, name);
					if (f != null && !isQueryIgnore(f)) {

						List<Bracket> brackets = getBrackets(f);
						List<Condition> conditions = getConditions(f);
						Like like = f.getAnnotation(Like.class);
						boolean hasBrackets = !brackets.isEmpty();
						boolean hasConditions = !conditions.isEmpty();
						boolean alone = false;

						if (hasBrackets) {
							for (Bracket b : brackets) {
								if (b.alone()) {
									alone = true;
									break;
								}
							}
						}

						if (null != like) {
							boolean prefix = like.prefix();
							boolean suffix = like.suffix();
							ValueOption vo = ValueOptionType.likeAll;
							if (prefix && !suffix) {
								vo = ValueOptionType.likeLeft;
							} else if (suffix && !prefix) {
								vo = ValueOptionType.likeRight;
							}
							ValueOptionInfo qvo = new ValueOptionInfo(name, vo);
							options.add(qvo);
						}

						if (hasBrackets) {
							for (Bracket b : brackets) {
								String group = b.group();
								BracketInfo bracketInfo = bracketMap.get(group);
								if (null == bracketInfo) {
									bracketInfo = new BracketInfo();
									bracketMap.put(group, bracketInfo);
								}

								if (hasConditions) {
									for (Condition c : conditions) {
										QueryColumn qc = getQueryColumn(name, c, like);
										bracketInfo.getColumns().add(qc);
									}
								} else {
									QueryColumn qc = getQueryColumn(name, null, like);
									bracketInfo.getColumns().add(qc);
								}
							}
						}

						if (!alone) {
							if (hasConditions) {
								for (Condition c : conditions) {
									QueryColumn qc = getQueryColumn(name, c, like);
									columns.add(qc);
								}
							} else {
								QueryColumn qc = getQueryColumn(name, null, like);
								columns.add(qc);
							}
						}
					}
				}
			}
		}

		List<BracketInfo> brackets = new ArrayList<>(bracketMap.values());

		data.setColumns(columns);
		data.setBrackets(brackets);
		data.setOrderByInfos(orderByInfos);
		data.setOptions(options);
		return data;
	}

	public static List<OrderByInfo> getOrderByInfos(Class<?> calssType) {
		List<OrderByInfo> orderByInfos = new ArrayList<>();
		OrderBy ob = calssType.getAnnotation(OrderBy.class);
		OrderBys obs = calssType.getAnnotation(OrderBys.class);
		OrderByInfo orderByInfo = getOrderByInfo(ob);
		if (null != orderByInfo) {
			orderByInfos.add(orderByInfo);
		}
		if (null != obs && null != obs.value() && obs.value().length > 0) {
			for (OrderBy v : obs.value()) {
				OrderByInfo obi = getOrderByInfo(v);
				if (null != obi) {
					orderByInfos.add(obi);
				}
			}
		}
		return orderByInfos;
	}

	public static OrderByInfo getOrderByInfo(OrderBy ob) {
		OrderByInfo orderByInfo = null;
		if (null != ob && null != ob.value() && ob.value().length > 0) {
			List<String> orderBys = new ArrayList<>();
			for (String v : ob.value()) {
				orderBys.add(v);
			}
			orderByInfo = new OrderByInfo();
			orderByInfo.setOrderByColumns(orderBys);
			orderByInfo.setSort((null == ob.sort()) ? null : ob.sort());
		}
		return orderByInfo;
	}

	public static Map<String, BracketInfo> getBracketInfoMap(Class<?> calssType) {
		Map<String, BracketInfo> map = new HashMap<>();
		BracketGroup a = calssType.getAnnotation(BracketGroup.class);
		BracketGroups as = calssType.getAnnotation(BracketGroups.class);
		BracketInfo info = getBracketInfo(a);
		if (null != info) {
			map.put(info.getGroup(), info);
		}
		if (null != as && null != as.value() && as.value().length > 0) {
			for (BracketGroup av : as.value()) {
				BracketInfo v = getBracketInfo(av);
				if (null != v) {
					map.put(v.getGroup(), v);
				}
			}
		}
		return map;
	}

	public static BracketInfo getBracketInfo(BracketGroup a) {
		BracketInfo info = null;
		if (null != a) {
			info = new BracketInfo();
			info.setGroup(a.group());
			info.setBind((a.bind() == null) ? null : a.bind().getValue());
		}
		return info;
	}

	public static List<Bracket> getBrackets(Field field) {
		List<Bracket> list = new ArrayList<>();
		Bracket a = field.getAnnotation(Bracket.class);
		Brackets as = field.getAnnotation(Brackets.class);
		if (null != a) {
			list.add(a);
		}

		if (null != as && null != as.value() && as.value().length > 0) {
			for (Bracket av : as.value()) {
				list.add(av);
			}
		}
		return list;
	}

	public static List<Condition> getConditions(Field field) {
		List<Condition> list = new ArrayList<>();
		Condition a = field.getAnnotation(Condition.class);
		Conditions as = field.getAnnotation(Conditions.class);
		if (null != a) {
			list.add(a);
		}

		if (null != as && null != as.value() && as.value().length > 0) {
			for (Condition av : as.value()) {
				list.add(av);
			}
		}
		return list;
	}

	public static QueryColumn getQueryColumn(String name, Condition c, Like like) {

		String column = null;

		QueryColumn qc = new QueryColumn();
		qc.setParameter(name);
		qc.setEquation(EquationType.eq.getValue());

		if (null != c) {
			column = c.column();
			String bind = (null == c.bind()) ? null : c.bind();

			qc.setBind(bind);
			qc.setEquation(c.equation());
		}

		if (null != like) {
			column = (DbStringUtil.isBlank(column)) ? like.column() : column;
			qc.setEquation(EquationType.like.getValue());
		}
		qc.setColumn(column);

		return qc;
	}

	public static boolean isQueryIgnore(Field field) {
		return null != field && null != field.getAnnotation(QueryIgnore.class);
	}
}
